函数 |
您所在的位置:网站首页 › close 和closure › 函数 |
1. 延迟调用(defer)1.1.1. Golang延迟调用:defer特性:defer用途:defer 碰上闭包defer f.Close1.1.2. defer陷阱defer 与 closuredefer 与 returndefer nil 函数在错误的位置使用 defer解决方案不检查错误
1. 延迟调用(defer)1.1.1. Golang延迟调用:defer特性: 1. 关键字 defer 用于注册延迟调用。 2. 这些调用直到 return 前才被执。因此,可以用来做资源清理。 3. 多个defer语句,按先进后出的方式执行。 4. defer语句中的变量,在defer声明时就决定了。
defer用途: 1. 关闭文件句柄 2. 锁资源释放 3. 数据库连接释放
go语言 defer go 语言的defer功能强大,对于资源管理非常方便,但是如果没用好,也会有陷阱。 defer 是先进后出 这个很自然,后面的语句会依赖前面的资源,因此如果先前面的资源先释放了,后面的语句就没法执行了。 package mainimport "fmt"func main() { var whatever [5]struct{} for i := range whatever { defer fmt.Println(i) }}输出结果: 4 3 2 1 0 defer 碰上闭包package mainimport "fmt"func main() { var whatever [5]struct{} for i := range whatever { defer func() { fmt.Println(i) }() }}输出结果: 4 4 4 4 4其实go说的很清楚,我们一起来看看go spec如何说的 Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usualand saved anew but the actual function is not invoked. 也就是说函数正常执行,由于闭包用到的变量 i 在执行的时候已经变成4,所以输出全都是4. defer f.Close这个大家用的都很频繁,但是go语言编程举了一个可能一不小心会犯错的例子. package mainimport "fmt"type Test struct { name string}func (t *Test) Close() { fmt.Println(t.name, " closed")}func main() { ts := []Test{{"a"}, {"b"}, {"c"}} for _, t := range ts { defer t.Close() }}输出结果: c closed c closed c closed这个输出并不会像我们预计的输出c b a,而是输出c c c 可是按照前面的go spec中的说明,应该输出c b a才对啊. 那我们换一种方式来调用一下. package mainimport "fmt"type Test struct { name string}func (t *Test) Close() { fmt.Println(t.name, " closed")}func Close(t Test) { t.Close()}func main() { ts := []Test{{"a"}, {"b"}, {"c"}} for _, t := range ts { defer Close(t) }}输出结果: c closed b closed a closed这个时候输出的就是c b a 当然,如果你不想多写一个函数,也很简单,可以像下面这样,同样会输出c b a 看似多此一举的声明 package mainimport "fmt"type Test struct { name string}func (t *Test) Close() { fmt.Println(t.name, " closed")}func main() { ts := []Test{{"a"}, {"b"}, {"c"}} for _, t := range ts { t2 := t defer t2.Close() }}输出结果: c closed b closed a closed通过以上例子,结合 Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usualand saved anew but the actual function is not invoked. 这句话。可以得出下面的结论: defer后面的语句在执行的时候,函数调用的参数会被保存起来,但是不执行。也就是复制了一份。但是并没有说struct这里的this指针如何处理,通过这个例子可以看出go语言并没有把这个明确写出来的this指针当作参数来看待。 多个 defer 注册,按 FILO 次序执行 ( 先进后出 )。哪怕函数或某个延迟调用发生错误,这些调用依旧会被执行。 package mainfunc test(x int) { defer println("a") defer println("b") defer func() { println(100 / x) // div0 异常未被捕获,逐步往外传递,最终终止进程。 }() defer println("c")}func main() { test(0)}输出结果: c b a panic: runtime error: integer divide by zero*延迟调用参数在注册时求值或复制,可用指针或闭包 "延迟" 读取。 package mainfunc test() { x, y := 10, 20 defer func(i int) { println("defer:", i, y) // y 闭包引用 }(x) // x 被复制 x += 10 y += 100 println("x =", x, "y =", y)}func main() { test()}输出结果: x = 20 y = 120 defer: 10 120*滥用 defer 可能会导致性能问题,尤其是在一个 "大循环" 里。 package mainimport ( "fmt" "sync" "time")var lock sync.Mutexfunc test() { lock.Lock() lock.Unlock()}func testdefer() { lock.Lock() defer lock.Unlock()}func main() { func() { t1 := time.Now() for i := 0; i |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |